package ncme.auto.framework.core.services.Impl.base;

import ncme.auto.framework.core.exceptions.AutoException;
import ncme.auto.framework.core.exceptions.ExceptionEnum;
import ncme.auto.framework.core.services.Impl.mian.AutoEntityServiceImpl;
import ncme.auto.framework.core.utils.BeanUtil;
import ncme.auto.framework.core.utils.ServiceUtil;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 实体映射关系基础服务类，各类映射规则需在实现类中进行限制
 *
 * @param <E>               映射实体类，命名为`Entity1`+`Entity2`+Mapper
 * @param <PRIMARY_CLASS>   Entity1，映射主从关系的`主`
 * @param <SECONDARY_CLASS> Entity2，映射主从关系的`从`
 */
public abstract class BaseAutoMapperServiceImpl<E, PRIMARY_CLASS, SECONDARY_CLASS> extends BaseAutoEntityServiceImpl<E> {

    @Autowired
    protected AutoEntityServiceImpl<PRIMARY_CLASS> primaryEntityBaseService;
    @Autowired
    protected AutoEntityServiceImpl<SECONDARY_CLASS> secondaryEntityBaseService;

    /**
     * 通过一方id获取映射实体
     *
     * @param id          primaryId或secondaryId
     * @param fromPrimary 若为true，则通过primaryId获取映射实体；若为false，则通过secondaryId获取映射实体
     * @return 映射实体们
     */
    protected List<E> getMappersFromId(Integer id, boolean fromPrimary) {
        try {
            return getEntitiesFromOneField(fromPrimary ? PRIMARY_FIELD_NAME : SECONDARY_FIELD_NAME, id);
        } catch (Exception e) {
            throw new AutoException(ExceptionEnum.AUTO_SERVICE_ERROR, "映射获取异常", e);
        }
    }

    /**
     * 通过一方id获取另一方ids
     *
     * @param originId                primaryId或secondaryId
     * @param getSecondaryFromPrimary 若为true，则通过primaryId获取secondaryIds；若为false，则通过secondaryId获取primaryIds
     * @return 另一方ids
     */
    public List<Integer> getIdsFromId(Integer originId, boolean getSecondaryFromPrimary) {
        try {
            List<E> targets = getMappersFromId(originId, getSecondaryFromPrimary);
            List<Integer> targetIds = new ArrayList<>();
            targets.forEach(target -> targetIds.add(BeanUtil.getFieldInteger(target, getSecondaryFromPrimary ? SECONDARY_FIELD_NAME : PRIMARY_FIELD_NAME)));
            return targetIds;
        } catch (Exception e) {
            throw new AutoException(ExceptionEnum.AUTO_SERVICE_ERROR, "映射Id获取异常", e);
        }
    }

    /**
     * 通过一方id获取另一方entities
     *
     * @param originId                primaryId或secondaryId
     * @param getSecondaryFromPrimary 若为true，则通过primaryId获取secondaryEntities；若为false，则通过secondaryId获取primaryEntities
     * @return 另一方entities
     */
    public List<Object> getEntitiesFromId(Integer originId, boolean getSecondaryFromPrimary) {
        try {
            List<Object> entities = new ArrayList<>();
            List<Integer> idsFromId = getIdsFromId(originId, getSecondaryFromPrimary);
            idsFromId.forEach(entityId -> entities.add((getSecondaryFromPrimary ? secondaryEntityBaseService : primaryEntityBaseService).getEntityById(entityId, false)));
            return entities;
        } catch (Exception e) {
            throw new AutoException(ExceptionEnum.AUTO_SERVICE_ERROR, "映射实体获取异常", e);
        }

    }

    /**
     * 添加实体映射
     *
     * @param masterId               主映射实体id
     * @param slaveIds               从映射实体ids
     * @param addSecondaryForPrimary 若为true，则添加primaryId与secondaryIds的映射；若为false，则添加secondaryId与primaryIds的映射；
     */
    protected void addMappers(Integer masterId, List<Integer> slaveIds, boolean addSecondaryForPrimary) {
        try {
            List<E> mappers = packageMappers(masterId, slaveIds, addSecondaryForPrimary);
            mappers.forEach(this::addEntity);
        } catch (Exception e) {
            throw new AutoException(ExceptionEnum.AUTO_SERVICE_ERROR, "映射添加异常", e);
        }
    }

    /**
     * 编辑实体映射，通过集合运算批量更改所有映射关系
     *
     * @param masterId               主映射实体id
     * @param slaveIds               从映射实体ids，需为最终添加的映射ids
     * @param editSecondaryOfPrimary 若为true，则编辑primaryId与secondaryIds的映射；若为false，则编辑secondaryId与primaryIds的映射；
     */
    protected void editMappers(Integer masterId, List<Integer> slaveIds, boolean editSecondaryOfPrimary) {
        try {
            List<Integer> oldSlaveIds = getIdsFromId(masterId, editSecondaryOfPrimary);
            deleteMappers(masterId, ServiceUtil.listSubtraction(oldSlaveIds, slaveIds), editSecondaryOfPrimary);
            addMappers(masterId, ServiceUtil.listSubtraction(slaveIds, oldSlaveIds), editSecondaryOfPrimary);
        } catch (Exception e) {
            throw new AutoException(ExceptionEnum.AUTO_SERVICE_ERROR, "映射更新异常", e);
        }
    }

    /**
     * 删除实体映射
     *
     * @param masterId                 主映射实体id
     * @param slaveIds                 从映射实体ids
     * @param deleteSecondaryOfPrimary 若为true，则删除primaryId与secondaryIds的映射；若为false，则删除secondaryId与primaryIds的映射；
     */
    protected void deleteMappers(Integer masterId, List<Integer> slaveIds, boolean deleteSecondaryOfPrimary) {
        try {
            List<E> mappers = packageMappers(masterId, slaveIds, deleteSecondaryOfPrimary);
            mappers.forEach(this::deleteEntity);
        } catch (Exception e) {
            throw new AutoException(ExceptionEnum.AUTO_SERVICE_ERROR, "映射删除异常", e);
        }
    }

    /**
     * 将id-ids关系包装为映射实体
     *
     * @param masterId   主映射实体id
     * @param slaveIds   从映射实体ids
     * @param forPrimary 若为true，则包装primaryId与secondaryIds的映射；若为false，则包装secondaryId与primaryIds的映射；
     * @return 包装后的映射实体们
     */
    private List<E> packageMappers(Integer masterId, List<Integer> slaveIds, boolean forPrimary) {
        try {
            (forPrimary ? primaryEntityBaseService : secondaryEntityBaseService).getEntityById(masterId, false);  //验证主映射实体是否存在
            List<E> mappers = new ArrayList<>();
            Map<String, Object> map = new HashMap<>();
            map.put(forPrimary ? PRIMARY_FIELD_NAME : SECONDARY_FIELD_NAME, masterId);
            map.put(forPrimary ? SECONDARY_FIELD_NAME : PRIMARY_FIELD_NAME, null);
            slaveIds.forEach(slaveId -> {
                (forPrimary ? secondaryEntityBaseService : primaryEntityBaseService).getEntityById(slaveId, false);  //验证从映射实体是否存在
                map.replace(forPrimary ? SECONDARY_FIELD_NAME : PRIMARY_FIELD_NAME, slaveId);
                mappers.add(createEntityFromMap(ENTITY_CLASS, map));
            });
            return mappers;
        } catch (Exception e) {
            throw new AutoException(ExceptionEnum.AUTO_SERVICE_ERROR, "映射实体包装异常", e);
        }
    }

    @Override
    public void addEntityOtherToRedis(E entity) {

    }

    @Override
    public void delEntityOtherFromRedis(E entity) {

    }

    /**
     * 由于映射字段不是唯一字段，因此将其添加为额外标识字段
     *
     * @return 额外标识字段primaryId和secondaryId
     */
    @Override
    public List<String> getFieldsForExtraRedisSet() {
        ArrayList<String> objects = new ArrayList<>();
        objects.add(PRIMARY_FIELD_NAME);
        objects.add(SECONDARY_FIELD_NAME);
        return objects;
    }

    @Override
    public List<String> getFieldsForExtraRedisSingleVerify() {
        return null;
    }

}
